/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "avro_napi.h"
#include <cstdint>
#include <iostream>
#include <mutex>
#include <regex>
#include <string>

#define BUFF_SIZE 1024
#define DOUBLE_BUFF_SIZE 2048
const int32_t STR_DEFAULT_SIZE = 2048;

std::mutex avro_writer_mutex;
bool g_IsParseSuccess = false;

napi_value AvroTypeC::Construct(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value argv[1] = {nullptr};

    napi_status status;
    napi_value jsthis;
    status = napi_get_cb_info(env, info, &argc, argv, &jsthis, nullptr);
    if (status != napi_ok) {
        LOGERROR("napi_get_cb_info failed!");
        g_IsParseSuccess = false;
        return nullptr;
    }

    std::string json_str = GetStringFromNapiValue(env, argv[0]);
    if (json_str.empty()) {
        LOGERROR(" GetStringFromNapiValuefailed!");
        g_IsParseSuccess = false;
        return nullptr;
    }

    AvroTypeC *ps = new AvroTypeC();
    ps->avroStr_ = json_str;

    avro_schema_error_t error;
    int ret = avro_schema_from_json(json_str.c_str(), 0, &ps->schema_, &error);
    if (ret != 0 || ps->schema_ == nullptr) {
        LOGERROR("Failed to parse Avro schema from JSON,ret=%{public}d", ret);
        g_IsParseSuccess = false;
        return nullptr;
    }

    status = napi_wrap(
        env, jsthis, ps,
        [](napi_env env, void *finalize_data, void *finalize_hint) {
            delete reinterpret_cast<AvroTypeC *>(finalize_data);
        },
        nullptr, nullptr);
    if (status != napi_ok || !ps) {
        LOGERROR("Invalid object instance");
        g_IsParseSuccess = false;
        return nullptr;
    }
    g_IsParseSuccess = true;
    return jsthis;
}

AvroTypeC::~AvroTypeC() {
    if (schema_ != nullptr) {
        avro_schema_decref(schema_);
    }
}

std::string AvroTypeC::GetStringFromNapiValue(napi_env env, napi_value value) {
    size_t length;
    napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &length);
    if (status != napi_ok) {
        LOGERROR("Failed to get string length");
        return nullptr;
    }

    char *buffer = new char[length + 1];
    size_t copied;
    status = napi_get_value_string_utf8(env, value, buffer, length + 1, &copied);
    if (status != napi_ok) {
        LOGERROR("Failed to get string value");
        delete[] buffer;
        return nullptr;
    }
    buffer[length] = '\0';

    std::string result = buffer;
    delete[] buffer;
    buffer = nullptr;

    const std::regex propPattern(R"(([{,]\s*)(\w+)(\s*:))");
    result = std::regex_replace(result, propPattern, "$1\"$2\"$3");

    const std::regex strPattern(R"('([^']+)')");
    result = std::regex_replace(result, strPattern, "\"$1\"");

    const std::regex valuePattern(R"(:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*([,}]))");
    result = std::regex_replace(result, valuePattern, ":\"$1\"$2");

    return result;
}

void AvroTypeC::ToBuffer_int32(napi_env env, napi_value args, avro_value_t *user_value) {
    int32_t value0;
    napi_status status = napi_get_value_int32(env, args, &value0);
    TOBUFFER_STATUS_CHECK(status);
    if (avro_value_set_int(user_value, value0)) {
        throw std::runtime_error("avro_value_set_int is failed");
    }
}

void AvroTypeC::ToBuffer_int64(napi_env env, napi_value args, avro_value_t *user_value) {
    int64_t value0;
    napi_status status = napi_get_value_int64(env, args, &value0);
    TOBUFFER_STATUS_CHECK(status);
    if (avro_value_set_long(user_value, value0)) {
        throw std::runtime_error("avro_value_set_long is failed");
    }
}

void AvroTypeC::ToBuffer_string(napi_env env, napi_value args, avro_value_t *user_value) {
    char buffer[BUFF_SIZE] = {0};
    size_t str_length = 0;

    napi_get_value_string_utf8(env, args, nullptr, 0, &str_length);

    if (str_length >= sizeof(buffer)) {
        throw std::runtime_error("tobuffer String too long!");
    }

    napi_status status = napi_get_value_string_utf8(env, args, buffer, sizeof(buffer), &str_length);
    TOBUFFER_STATUS_CHECK(status);

    if (avro_value_set_string_len(user_value, buffer, strlen(buffer) + 1)) {
        throw std::runtime_error("avro_value_set_string_len is failed");
    }
}

void AvroTypeC::ToBuffer_float(napi_env env, napi_value args, avro_value_t *user_value) {
    double value0;
    napi_status status = napi_get_value_double(env, args, &value0);
    TOBUFFER_STATUS_CHECK(status);
    float value_float = float(value0);
    if (avro_value_set_float(user_value, value_float)) {
        throw std::runtime_error("avro_value_set_float is failed");
    }
}

void AvroTypeC::ToBuffer_double(napi_env env, napi_value args, avro_value_t *user_value) {
    double value0;
    napi_status status = napi_get_value_double(env, args, &value0);
    TOBUFFER_STATUS_CHECK(status);
    if (avro_value_set_double(user_value, value0)) {
        throw std::runtime_error("avro_value_set_double is failed");
    }
}

void AvroTypeC::ToBuffer_boolean(napi_env env, napi_value args, avro_value_t *user_value) {
    bool value0;
    napi_status status = napi_get_value_bool(env, args, &value0);
    TOBUFFER_STATUS_CHECK(status);
    if (avro_value_set_boolean(user_value, value0)) {
        throw std::runtime_error("avro_value_set_boolean is failed");
    }
}

void AvroTypeC::ToBuffer_null(napi_env env, napi_value args, avro_value_t *user_value) {
    if (avro_value_set_null(user_value)) {
        throw std::runtime_error("avro_value_set_null is failed");
    }
}

void AvroTypeC::ToBuffer_enum(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value) {
    char buffer[BUFF_SIZE] = {0};
    size_t str_length = 0;
    napi_status status;

    status = napi_get_value_string_utf8(env, args, nullptr, 0, &str_length);
    TOBUFFER_STATUS_CHECK(status);

    if (str_length >= sizeof(buffer)) {
        throw std::runtime_error("enum String is too long!");
    }

    status = napi_get_value_string_utf8(env, args, buffer, sizeof(buffer), &str_length);
    TOBUFFER_STATUS_CHECK(status);

    int enum_index = avro_schema_enum_get_by_name(schema, buffer);
    if (enum_index == -1) {
        throw std::runtime_error("avro_schema_enum_get_by_name is failed");
    }

    if (avro_value_set_enum(user_value, enum_index)) {
        throw std::runtime_error("avro_value_set_enum is failed");
    }
}

void Fill_map(avro_type_t value_type, uint32_t length, napi_env env, napi_value entries_iterator, napi_value next_func,
              avro_value_t *user_value, avro_schema_t values_schema) {
    napi_status status;

    for (int i = 0; i < length; i++) {
        napi_value next_result;
        status = napi_call_function(env, entries_iterator, next_func, 0, nullptr, &next_result);
        TOBUFFER_STATUS_CHECK(status);

        napi_value done_prop;
        status = napi_get_named_property(env, next_result, "done", &done_prop);
        TOBUFFER_STATUS_CHECK(status);

        bool done;
        status = napi_get_value_bool(env, done_prop, &done);
        TOBUFFER_STATUS_CHECK(status);

        if (done)
            break;

        napi_value value_prop;
        status = napi_get_named_property(env, next_result, "value", &value_prop);
        TOBUFFER_STATUS_CHECK(status);

        napi_value key;
        napi_value args = nullptr;
        status = napi_get_element(env, value_prop, 0, &key);
        TOBUFFER_STATUS_CHECK(status);
        status = napi_get_element(env, value_prop, 1, &args);
        TOBUFFER_STATUS_CHECK(status);

        char key1[BUFF_SIZE] = {0};
        size_t len = 0;
        status = napi_get_value_string_utf8(env, key, key1, BUFF_SIZE, &len);
        TOBUFFER_STATUS_CHECK(status);

        avro_value_t item_value;
        if (avro_value_add(user_value, key1, &item_value, NULL, NULL) == 0) {
            AvroTypeC::ToBuffer_recursion(value_type, env, values_schema, args, &item_value);
        } else {
            throw std::runtime_error("push into map is error");
        }
    }
}

void Fill_array(avro_type_t value_type, uint32_t length, napi_env env, napi_value args, avro_value_t *user_value,
                avro_schema_t values_schema) {
    napi_status status;
    for (int i = 0; i < length; i++) {
        napi_value argc = nullptr;
        status = napi_get_element(env, args, i, &argc);
        TOBUFFER_STATUS_CHECK(status);

        avro_value_t item_value;
        if (avro_value_append(user_value, &item_value, NULL) == 0) {
            AvroTypeC::ToBuffer_recursion(value_type, env, values_schema, argc, &item_value);
        } else {
            throw std::runtime_error("push into array is error");
        }
    }
}

void AvroTypeC::ToBuffer_map(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value) {
    avro_type_t value_type;
    napi_status status;

    avro_schema_t values_schema = avro_schema_map_values(schema);
    value_type = values_schema->type;

    napi_value size_prop;
    status = napi_get_named_property(env, args, "size", &size_prop);
    TOBUFFER_STATUS_CHECK(status);

    uint32_t map_size;
    status = napi_get_value_uint32(env, size_prop, &map_size);
    TOBUFFER_STATUS_CHECK(status);

    napi_value entries_func;
    status = napi_get_named_property(env, args, "entries", &entries_func);
    TOBUFFER_STATUS_CHECK(status);

    napi_value entries_iterator;
    status = napi_call_function(env, args, entries_func, 0, nullptr, &entries_iterator);
    TOBUFFER_STATUS_CHECK(status);

    napi_value next_func;
    status = napi_get_named_property(env, entries_iterator, "next", &next_func);
    TOBUFFER_STATUS_CHECK(status);

    Fill_map(value_type, map_size, env, entries_iterator, next_func, user_value, values_schema);
}

void AvroTypeC::ToBuffer_record(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value) {
    avro_type_t value_type;
    napi_status status;

    int32_t fields_count = avro_schema_record_size(schema);

    napi_value nameArray;
    status = napi_get_property_names(env, args, &nameArray);
    TOBUFFER_STATUS_CHECK(status);

    uint32_t length = 0;
    status = napi_get_array_length(env, nameArray, &length);
    TOBUFFER_STATUS_CHECK(status);

    for (int i = 0; i < fields_count; i++) {
        avro_value_t name_field;
        napi_value argc = nullptr;
        const char *name = avro_schema_record_field_name(schema, i);
        avro_schema_t field_schema = avro_schema_record_field_get_by_index(schema, i);
        value_type = field_schema->type;

        if (avro_value_get_by_name(user_value, name, &name_field, NULL) != 0) {
            throw std::runtime_error("record has no name match");
        }

        status = napi_get_named_property(env, args, name, &argc);
        TOBUFFER_STATUS_CHECK(status);

        AvroTypeC::ToBuffer_recursion(value_type, env, field_schema, argc, &name_field);
    }
}

void AvroTypeC::ToBuffer_array(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value) {
    avro_type_t value_type;
    napi_status status;

    avro_schema_t values_schema = avro_schema_array_items(schema);
    value_type = values_schema->type;

    uint32_t length = 0;
    status = napi_get_array_length(env, args, &length);
    TOBUFFER_STATUS_CHECK(status);

    Fill_array(value_type, length, env, args, user_value, values_schema);
}

void AvroTypeC::ToBuffer_fixed(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value) {
    napi_status status;

    uint32_t length = 0;
    status = napi_get_array_length(env, args, &length);
    TOBUFFER_STATUS_CHECK(status);

    int64_t size_schema = avro_schema_fixed_size(schema);

    if (size_schema != length) {
        throw std::runtime_error("the fixed data length does not match the schema");
    }

    std::vector<uint8_t> fixed_data;
    fixed_data.reserve(length);

    for (int i = 0; i < length; i++) {
        napi_value key;
        status = napi_get_element(env, args, i, &key);
        TOBUFFER_STATUS_CHECK(status);

        uint32_t num_value;
        status = napi_get_value_uint32(env, key, &num_value);
        TOBUFFER_STATUS_CHECK(status);

        fixed_data.push_back(static_cast<uint8_t>(num_value));
    }

    if (avro_value_set_fixed(user_value, fixed_data.data(), length)) {
        throw std::runtime_error("avro_value_set_fixed is failed");
    }
}

void AvroTypeC::ToBuffer_bytes(napi_env env, napi_value args, avro_value_t *user_value) {
    napi_status status;
    uint32_t length = 0;
    status = napi_get_array_length(env, args, &length);
    TOBUFFER_STATUS_CHECK(status);

    std::vector<uint8_t> bytes_data;
    bytes_data.reserve(length);

    for (int i = 0; i < length; i++) {
        napi_value key;
        status = napi_get_element(env, args, i, &key);
        TOBUFFER_STATUS_CHECK(status);

        uint32_t num_value;
        status = napi_get_value_uint32(env, key, &num_value);
        TOBUFFER_STATUS_CHECK(status);

        bytes_data.push_back(static_cast<uint8_t>(num_value));
    }

    if (avro_value_set_bytes(user_value, bytes_data.data(), length)) {
        throw std::runtime_error("avro_value_set_bytes is failed");
    }
}

bool isInteger(double value) { return std::floor(value) == value; }

bool isSafeInteger(double value) {
    return isInteger(value) && value >= std::numeric_limits<int64_t>::min() &&
           value <= std::numeric_limits<int64_t>::max();
}

bool isInt32(double value) {
    return isInteger(value) && value >= std::numeric_limits<int32_t>::min() &&
           value <= std::numeric_limits<int32_t>::max();
}

bool isFloat(double value) {
    float fValue = static_cast<float>(value);
    return std::abs(value - static_cast<double>(fValue)) < 1e-6;
}

std::string getJsNumberType(double value) {
    if (isInteger(value)) {
        if (isInt32(value)) {
            return "int";
        } else if (isSafeInteger(value)) {
            return "long";
        } else {
            return "bigint (超出 int64 范围)";
        }
    } else {
        if (isFloat(value)) {
            return "float";
        } else {
            return "double";
        }
    }
}

bool ValidateNumBerSupport(napi_env env, napi_value data, std::string &type_name, avro_type_t &avro_type,
                           avro_schema_t all_schema) {
    if (AvroTypeC::ValidateNumber(env, data)) {
        double value0;
        napi_get_value_double(env, data, &value0);
        std::string name = getJsNumberType(value0);
        int branch_count = avro_schema_union_size(all_schema);
        for (int i = 0; i < branch_count; i++) {
            avro_schema_t branch = avro_schema_union_branch(all_schema, i);
            if ((branch->type == AVRO_DOUBLE || branch->type == AVRO_FLOAT) && (name == "double" || name == "float")) {
                switch (branch->type) {
                case AVRO_DOUBLE:
                    type_name = "double";
                    break;
                case AVRO_FLOAT:
                    type_name = "float";
                    break;
                default:
                    type_name = "double";
                }
            } else if ((branch->type == AVRO_INT32 || branch->type == AVRO_INT64) &&
                       (name == "long" || name == "int")) {
                switch (branch->type) {
                case AVRO_INT32:
                    type_name = "int";
                    break;
                case AVRO_INT64:
                    type_name = "long";
                    break;
                default:
                    type_name = "long";
                }
            }
            if (type_name != "") {
                avro_type = branch->type;
                return true;
            }
        }
    }
    return false;
}

bool AvroTypeC::DataAgainstSchema(napi_env env, napi_value data, avro_schema_t schema, std::string &type_name,
                                  avro_type_t &avro_type, avro_schema_t all_schema) {
    switch (schema->type) {
    case AVRO_RECORD:
        if (ValidateRecord(env, data, schema)) {
            type_name = "record";
            avro_type = AVRO_RECORD;
            return true;
        }
        break;
    case AVRO_STRING:
        if (ValidateString(env, data)) {
            type_name = "string";
            avro_type = AVRO_STRING;
            return true;
        }
        break;
    case AVRO_DOUBLE:
        if (ValidateNumBerSupport(env, data, type_name, avro_type, all_schema)) {
            return true;
        }
        break;
    case AVRO_INT32:
        if (ValidateNumBerSupport(env, data, type_name, avro_type, all_schema)) {
            return true;
        }
        break;
    case AVRO_INT64:
        if (ValidateNumBerSupport(env, data, type_name, avro_type, all_schema)) {
            return true;
        }
        break;
    case AVRO_FLOAT:
        if (ValidateNumBerSupport(env, data, type_name, avro_type, all_schema)) {
            return true;
        }
        break;
    case AVRO_BOOLEAN:
        if (ValidateBoolean(env, data)) {
            type_name = "boolean";
            avro_type = AVRO_BOOLEAN;
            return true;
        }
        break;
    case AVRO_ARRAY:
        if (ValidateArray(env, data, schema)) {
            type_name = "array";
            avro_type = AVRO_ARRAY;
            return true;
        }
        break;
    case AVRO_MAP:
        if (ValidateMap(env, data, schema)) {
            type_name = "map";
            avro_type = AVRO_MAP;
            return true;
        }
        break;
    case AVRO_UNION:
        if (ValidateUnion(env, data, schema)) {
            type_name = "union";
            avro_type = AVRO_UNION;
            return true;
        }
        break;
    case AVRO_BYTES:
        if (ValidateBytes(env, data)) {
            type_name = "bytes";
            avro_type = AVRO_BYTES;
            return true;
        }
        break;
    case AVRO_FIXED:
        if (ValidateFixed(env, data, schema)) {
            type_name = "fixed";
            avro_type = AVRO_FIXED;
            return true;
        }
        break;
    case AVRO_ENUM:
        if (ValidateEnum(env, data, schema)) {
            type_name = "enum";
            avro_type = AVRO_ENUM;
            return true;
        }
        break;
    case AVRO_NULL:
        if (ValidateNull(env, data)) {
            type_name = "null";
            avro_type = AVRO_NULL;
            return true;
        }
        break;
    default:
        return false;
    }
    return false;
}

void AvroTypeC::ToBuffer_union(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value) {
    avro_schema_t branch_schema;
    int found_index;
    avro_value_t branch_value;
    std::string type_name = "";
    avro_type_t avro_type;

    int branch_count = avro_schema_union_size(schema);
    for (int i = 0; i < branch_count; i++) {
        avro_schema_t branch = avro_schema_union_branch(schema, i);
        if (AvroTypeC::DataAgainstSchema(env, args, branch, type_name, avro_type, schema)) {
            break;
        } else {
            continue;
        }
    }
    branch_schema = avro_schema_union_branch_by_name(schema, &found_index, type_name.c_str());
    if (found_index > branch_count || found_index == branch_count || type_name == "") {
        throw std::runtime_error("union branch match failed");
    }
    if (avro_value_set_branch(user_value, found_index, &branch_value) != 0) {
        throw std::runtime_error("union set branch failed");
    }
    AvroTypeC::ToBuffer_recursion(avro_type, env, branch_schema, args, &branch_value);
}

void AvroTypeC::ToBuffer_recursion(avro_type_t value_type, napi_env env, avro_schema_t schema, napi_value args,
                                   avro_value_t *user_value) {
    switch (value_type) {
    case AVRO_INT32:
        ToBuffer_int32(env, args, user_value);
        break;
    case AVRO_INT64:
        ToBuffer_int64(env, args, user_value);
        break;
    case AVRO_STRING:
        ToBuffer_string(env, args, user_value);
        break;
    case AVRO_FLOAT:
        ToBuffer_float(env, args, user_value);
        break;
    case AVRO_DOUBLE:
        ToBuffer_double(env, args, user_value);
        break;
    case AVRO_BOOLEAN:
        ToBuffer_boolean(env, args, user_value);
        break;
    case AVRO_NULL:
        ToBuffer_null(env, args, user_value);
        break;
    case AVRO_ENUM:
        ToBuffer_enum(env, schema, args, user_value);
        break;
    case AVRO_MAP:
        ToBuffer_map(env, schema, args, user_value);
        break;
    case AVRO_ARRAY:
        ToBuffer_array(env, schema, args, user_value);
        break;
    case AVRO_FIXED:
        ToBuffer_fixed(env, schema, args, user_value);
        break;
    case AVRO_RECORD:
        ToBuffer_record(env, schema, args, user_value);
        break;
    case AVRO_BYTES:
        ToBuffer_bytes(env, args, user_value);
        break;
    case AVRO_UNION:
        ToBuffer_union(env, schema, args, user_value);
        break;
    default:
        throw std::runtime_error("ToBuffer_recursion Dont match schema type");
    }
}

napi_value AvroTypeC::ToBuffer(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_value jsthis;
    avro_value_t user_value = {0};
    avro_writer_t writer = NULL;
    avro_value_iface_t *iface = NULL;
    char *buf = nullptr;
    napi_value arraybuffer;
    try {
        napi_status status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr);
        if (status != napi_ok || argc < 1) {
            throw std::runtime_error("Expected 1 argument (ToBuffer)");
        }

        AvroTypeC *obj;
        status = napi_unwrap(env, jsthis, (void **)&obj);
        TOBUFFER_STATUS_CHECK(status);

        if (obj->schema_ == nullptr) {
            throw std::runtime_error("schema is nullptr");
        }

        iface = avro_generic_class_from_schema(obj->schema_);
        int generic_status = avro_generic_value_new(iface, &user_value);
        if (generic_status != 0) {
            throw std::runtime_error("avro_generic_value_new is failed");
        }

        AvroTypeC::ToBuffer_recursion(obj->schema_->type, env, obj->schema_, args[0], &user_value);

        buf = (char *)malloc(BUFF_SIZE);

        writer = avro_writer_memory(buf, sizeof(buf) * 64);

        int write_status = avro_value_write(writer, &user_value);
        if (write_status != 0) {
            throw std::runtime_error("avro_value_write is failed");
        }

        void *buffer_data = nullptr;
        size_t str_buf = avro_writer_tell(writer);

        status = napi_create_arraybuffer(env, str_buf, &buffer_data, &arraybuffer);
        TOBUFFER_STATUS_CHECK(status);
        memcpy(buffer_data, buf, str_buf);
    } catch (const std::exception &e) {
        if (buf != nullptr) {
            free(buf);
        }
        if (writer != nullptr) {
            avro_writer_free(writer);
        }
        if (user_value.iface) {
            avro_value_decref(&user_value);
        }
        if (iface != nullptr) {
            avro_value_iface_decref(iface);
        }
        LOGERROR("TOBUFFER ERROR: %{public}s", e.what());
        return nullptr;
    }
    if (buf != nullptr) {
        free(buf);
    }
    if (writer) {
        avro_writer_free(writer);
    }
    if (user_value.iface) {
        avro_value_decref(&user_value);
    }
    if (iface) {
        avro_value_iface_decref(iface);
    }
    return arraybuffer;
}

int create_avro_value(avro_schema_t schema, avro_value_iface_t **iface, avro_value_t *value) {
    *iface = avro_generic_class_from_schema(schema);
    if (*iface == NULL) {
        return -1;
    }
    if (avro_generic_value_new(*iface, value)) {
        avro_value_iface_decref(*iface);
        return -1;
    }

    return 0;
}

int serialize_single_to_file(avro_schema_t schema, napi_value arg, napi_env env,
                             std::vector<avro_value_t> &write_values) {
    avro_value_iface_t *iface = NULL;
    avro_value_t value;

    if (create_avro_value(schema, &iface, &value)) {
        return -1;
    }

    AvroTypeC::ToBuffer_recursion(schema->type, env, schema, arg, &value);

    avro_value_t dest;
    int generic_status = avro_generic_value_new(iface, &dest);
    if (generic_status != 0) {
        throw std::runtime_error("avro_generic_value_new is failed");
    }
    avro_value_copy(&dest, &value);
    write_values.push_back(dest);

    avro_value_decref(&value);
    avro_value_iface_decref(iface);

    return 0;
}

void WriteAvroWorker(napi_env env, void *data) {
    std::lock_guard<std::mutex> lock(avro_writer_mutex);
    AvroAsyncData *asyncData = static_cast<AvroAsyncData *>(data);
    if (asyncData == nullptr)
        return;

    if (asyncData->hasError || asyncData->shouldAbort) {
        asyncData->errorMsg = "Operation aborted due to main thread error";
        return;
    }

    int success_count = 0;
    int fail_count = 0;

    for (int i = 0; i < asyncData->write_values.size(); i++) {
        int ret1 = avro_file_writer_append_value(asyncData->writer, &asyncData->write_values[i]);
        if (ret1 == 0) {
            success_count++;
        } else {
            fail_count++;
        }
    }
    if (avro_file_writer_flush(asyncData->writer)) {
        LOGERROR("Failed to avro_file_writer_flush");
    }
    if (fail_count != napi_ok || asyncData->writer == nullptr) {
        asyncData->errorMsg = "Failed to avro_file_writer_append_value";
        LOGERROR("Failed to avro_file_writer_append_value,fail_count:%{public}d", fail_count);
        return;
    }
}

void WriteAvroComplete(napi_env env, napi_status status, void *data) {
    AvroAsyncData *asyncData = static_cast<AvroAsyncData *>(data);
    if (asyncData == nullptr || asyncData->callback == nullptr) {
        FreeAvroAsyncData(env, asyncData);
        return;
    }

    napi_value callbackArgs[2];
    napi_get_null(env, &callbackArgs[0]);
    napi_create_string_utf8(env, "File written complete", NAPI_AUTO_LENGTH, &callbackArgs[1]);

    if (!asyncData->errorMsg.empty()) {
        napi_create_string_utf8(env, asyncData->errorMsg.c_str(), asyncData->errorMsg.length(), &callbackArgs[0]);
        napi_get_null(env, &callbackArgs[1]);
    }

    napi_value callback;
    napi_get_reference_value(env, asyncData->callback, &callback);

    napi_value global;
    napi_get_global(env, &global);
    napi_call_function(env, global, callback, 2, callbackArgs, nullptr);

    FreeAvroAsyncData(env, asyncData);
}

napi_value SerializeToFile(napi_env env, napi_callback_info info) {
    std::string file_schema_string;
    std::string file_codec;
    size_t argc = 5;
    napi_value args[5] = {nullptr};
    napi_status status;
    avro_value_t user_value = {0};
    avro_value_iface_t *iface = NULL;
    AvroAsyncData *asyncData = static_cast<AvroAsyncData *>(calloc(1, sizeof(AvroAsyncData)));
    try {
        if (asyncData == nullptr) {
            throw std::runtime_error("asyncData init failed");
        }
        status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
        if (status != napi_ok || argc < 5) {
            throw std::runtime_error("SerializeToFile:Get cb failed！");
        }
        NapiUtil::JsValueToString(env, args[0], STR_DEFAULT_SIZE, asyncData->filePath);
        if (asyncData->filePath.empty()) {
            throw std::runtime_error("SerializeToFile:file_path is null");
        }
        file_schema_string = AvroTypeC::GetStringFromNapiValue(env, args[1]);
        if (file_schema_string.empty()) {
            throw std::runtime_error("SerializeToFile:file_schema_string is null");
        }
        NapiUtil::JsValueToString(env, args[3], STR_DEFAULT_SIZE, file_codec);
        if (file_codec.empty() ||
            (file_codec != "deflate" && file_codec != "lzma" && file_codec != "snappy" && file_codec != "null")) {
            throw std::runtime_error("SerializeToFile:file_codec is null or invalid");
        }
        avro_schema_error_t error;
        int ret = avro_schema_from_json(file_schema_string.c_str(), 0, &asyncData->schema, &error);
        if (ret != 0 || asyncData->schema == nullptr) {
            throw std::runtime_error("SerializeToFile:Failed to parse Avro schema from JSON");
        }
        iface = avro_generic_class_from_schema(asyncData->schema);
        int generic_status = avro_generic_value_new(iface, &user_value);
        if (generic_status != 0) {
            throw std::runtime_error("avro_generic_value_new is failed");
        }
        int ret_writer = 0;
        if (file_codec == "null") {
            ret_writer = avro_file_writer_create(asyncData->filePath.c_str(), asyncData->schema, &asyncData->writer);
        } else {
            ret_writer = avro_file_writer_create_with_codec(asyncData->filePath.c_str(), asyncData->schema,
                                                            &asyncData->writer, file_codec.c_str(), 64 * BUFF_SIZE);
        }
        if (ret_writer) {
            throw std::runtime_error("Failed to create Avro file writer");
        }
        if (asyncData->schema->type == AVRO_RECORD) {
            napi_status status;
            bool isArray;
            napi_is_array(env, args[2], &isArray);
            if (!isArray) {
                throw std::runtime_error("record type should be included in an array pls");
            }
            uint32_t length = 0;
            status = napi_get_array_length(env, args[2], &length);
            TOBUFFER_STATUS_CHECK(status);
            for (int i = 0; i < length; i++) {
                napi_value argc = nullptr;
                status = napi_get_element(env, args[2], i, &argc);
                TOBUFFER_STATUS_CHECK(status);
                if (serialize_single_to_file(asyncData->schema, argc, env, asyncData->write_values)) {
                    throw std::runtime_error("serialize_single_to_file is failed");
                }
            }
        } else {
            AvroTypeC::ToBuffer_recursion(asyncData->schema->type, env, asyncData->schema, args[2], &user_value);
            avro_value_t dest;
            int generic_status = avro_generic_value_new(iface, &dest);
            if (generic_status != 0) {
                throw std::runtime_error("avro_generic_value_new is failed");
            }
            avro_value_copy(&dest, &user_value);
            asyncData->write_values.push_back(dest);
        }
        napi_create_reference(env, args[4], 1, &asyncData->callback);

        napi_value resourceName;
        napi_create_string_utf8(env, "WriteAvroWorker", NAPI_AUTO_LENGTH, &resourceName);
        if (napi_create_async_work(env, nullptr, resourceName, WriteAvroWorker, WriteAvroComplete, asyncData,
                                   &asyncData->work) != napi_ok) {
            throw std::runtime_error("napi_create_async_work Failed");
        }

        napi_queue_async_work(env, asyncData->work);
    } catch (const std::exception &e) {
        if (asyncData != nullptr) {
            asyncData->hasError = true;

            if (asyncData->work == nullptr) {
                FreeAvroAsyncData(env, asyncData);
                asyncData = nullptr;
            } else {
                asyncData->shouldAbort = true;
            }
        }
        if (user_value.iface) {
            avro_value_decref(&user_value);
        }
        if (iface != nullptr) {
            avro_value_iface_decref(iface);
        }
        napi_throw_error(env, NULL, e.what());
        return nullptr;
    }
    if (user_value.iface) {
        avro_value_decref(&user_value);
    }
    if (iface != nullptr) {
        avro_value_iface_decref(iface);
    }

    return nullptr;
}

napi_value AvroTypeC::GetSchemaTypeName(napi_env env, napi_callback_info info) {
    napi_value jsthis;
    napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr);
    if (status != napi_ok) {
        LOGERROR("Get cb failed!");
        return nullptr;
    }

    AvroTypeC *obj;
    status = napi_unwrap(env, jsthis, (void **)&obj);
    if (status != napi_ok || obj == nullptr) {
        return nullptr;
    }

    avro_schema_t schema = obj->schema_;

    const char *type = avro_schema_type_name(schema);
    napi_value result;
    status = napi_create_string_utf8(env, type, NAPI_AUTO_LENGTH, &result);
    if (status != napi_ok) {
        LOGERROR("Failed to create string result!");
        return nullptr;
    }
    return result;
}

napi_value AvroTypeC::GetArrayItemType(napi_env env, napi_callback_info info) {
    napi_value jsthis;

    napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr);
    if (status != napi_ok) {
        LOGERROR("Get cb failed!");
        return nullptr;
    }

    AvroTypeC *obj;
    status = napi_unwrap(env, jsthis, (void **)&obj);
    if (status != napi_ok) {
        LOGERROR("unwrap failed!");
        return nullptr;
    }

    avro_schema_t schema = obj->schema_;
    const char *type_name = avro_schema_type_name(schema);
    if (strcmp(type_name, "array") != 0) {
        LOGERROR("Is not array（is %{public}s)", type_name);
        return nullptr;
    }

    avro_schema_t item_schema = avro_schema_array_items(schema);
    if (item_schema == nullptr) {
        LOGERROR("Get item schema failed!");
        return nullptr;
    }

    const char *item_type = avro_schema_type_name(item_schema);
    if (item_type == nullptr) {
        LOGERROR("Get item type failed！");
        return nullptr;
    }

    napi_value result;
    status = napi_create_string_utf8(env, item_type, NAPI_AUTO_LENGTH, &result);
    if (status != napi_ok) {
        LOGERROR("Failed to create GetArrayItemType result!");
        return nullptr;
    }
    return result;
}

napi_value AvroTypeC::GetMapValueType(napi_env env, napi_callback_info info) {
    napi_value jsthis;

    napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr);
    if (status != napi_ok) {
        LOGERROR("Get cb failed!");
        return nullptr;
    }

    AvroTypeC *obj;
    status = napi_unwrap(env, jsthis, (void **)&obj);
    if (status != napi_ok) {
        LOGERROR("Unwrap failed!");
        return nullptr;
    }

    avro_schema_t schema = obj->schema_;
    const char *type_name = avro_schema_type_name(schema);
    if (strcmp(type_name, "map") != 0) {
        LOGERROR("Is not map（is %{public}s）", type_name);
        return nullptr;
    }

    avro_schema_t item_schema = avro_schema_map_values(schema);
    if (item_schema == nullptr) {
        LOGERROR("Get item schema failed!");
        return nullptr;
    }
    const char *item_type = avro_schema_type_name(item_schema);
    if (item_type == nullptr) {
        LOGERROR("Get schema type failed!");
        return nullptr;
    }

    napi_value result;
    status = napi_create_string_utf8(env, item_type, NAPI_AUTO_LENGTH, &result);
    if (status != napi_ok) {
        LOGERROR("Failed to create string result!");
        return nullptr;
    }
    return result;
}

napi_value AvroTypeC::GetFixedSize(napi_env env, napi_callback_info info) {
    napi_value jsthis;
    napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr);
    if (status != napi_ok) {
        LOGERROR("Get cb failed!");
        return nullptr;
    }

    AvroTypeC *obj;
    status = napi_unwrap(env, jsthis, (void **)&obj);
    if (status != napi_ok) {
        LOGERROR("Unwrap failed!");
        return nullptr;
    }

    avro_schema_t schema = obj->schema_;

    if (!NapiUtil::IsFixedTypeByavroStr(obj->avroStr_)) {
        LOGERROR("Is not fixed!");
        return nullptr;
    }

    size_t fixed_size = avro_schema_fixed_size(schema); // 获取长度
    napi_value result;
    status = napi_create_int32(env, fixed_size, &result);
    if (status != napi_ok) {
        LOGERROR("Failed to create int result!");
        return nullptr;
    }

    return result;
}

bool AvroTypeC::ValidateString(napi_env env, napi_value value) {
    napi_valuetype type;
    napi_typeof(env, value, &type);
    return type == napi_string;
}

bool AvroTypeC::ValidateNumber(napi_env env, napi_value value) {
    napi_valuetype type;
    napi_typeof(env, value, &type);
    return type == napi_number;
}

bool AvroTypeC::ValidateBoolean(napi_env env, napi_value value) {
    napi_valuetype type;
    napi_typeof(env, value, &type);
    return type == napi_boolean;
}

bool AvroTypeC::ValidateRecord(napi_env env, napi_value data, avro_schema_t schema) {
    napi_valuetype type;
    napi_typeof(env, data, &type);
    if (type != napi_object) {
        LOGERROR("Is not record!");
        return false;
    }
    int fieldCount = avro_schema_record_size(schema);
    for (int i = 0; i < fieldCount; i++) {
        const char *fieldName = avro_schema_record_field_name(schema, i);
        if (fieldName == nullptr) {
            LOGERROR("Get record fieldname failed!");
            return false;
        }
        avro_schema_t fieldSchema = avro_schema_record_field_get_by_index(schema, i);

        bool hasProperty;
        napi_has_named_property(env, data, fieldName, &hasProperty);
        if (!hasProperty) {
            LOGERROR("Not find filed(%{public}s)!", fieldName);
            return false;
        }

        napi_value fieldValue;
        napi_get_named_property(env, data, fieldName, &fieldValue);
        if (!ValidateDataAgainstSchema(env, fieldValue, fieldSchema)) {
            return false;
        }
    }
    return true;
}

bool AvroTypeC::ValidateArray(napi_env env, napi_value data, avro_schema_t schema) {
    if (!NapiUtil::IsArray(env, data)) {
        return false;
    }
    avro_schema_t itemsSchema = avro_schema_array_items(schema);
    uint32_t length;
    napi_status status = napi_get_array_length(env, data, &length);
    if (status != napi_ok) {
        LOGERROR("Failed to get arraylen!");
        return false;
    }

    for (uint32_t i = 0; i < length; i++) {
        napi_value element;
        napi_get_element(env, data, i, &element);
        if (!ValidateDataAgainstSchema(env, element, itemsSchema)) {
            return false;
        }
    }

    return true;
}

bool AvroTypeC::ValidateMap(napi_env env, napi_value data, avro_schema_t schema) {
    if (!NapiUtil::IsMap(env, data)) {
        return false;
    }
    napi_value property_names;
    if (napi_get_property_names(env, data, &property_names) != napi_ok) {
        LOGERROR("Get property name of map failed!");
        return false;
    }
    uint32_t property_count;
    if (napi_get_array_length(env, property_names, &property_count) != napi_ok) {
        LOGERROR("Get length failed!");
        return false;
    }
    avro_schema_t value_schema = avro_schema_map_values(schema);
    if (!value_schema) {
        LOGERROR("Invalid map value！");
        return false;
    }
    bool all_valid = true;
    for (uint32_t i = 0; i < property_count; i++) {
        napi_value property_name;
        if (napi_get_element(env, property_names, i, &property_name) != napi_ok) {
            LOGERROR("Get element failed!");
            return false;
        }

        napi_valuetype key_type;
        if (napi_typeof(env, property_name, &key_type) != napi_ok) {
            LOGERROR("Get element type failed!");
            return false;
        }
        if (key_type != napi_string) {
            LOGINFO("[%{public}s] The key of the map must be of the string type！", __func__);
            all_valid = false;
            return false;
        }
        char key_name[1024];
        size_t key_len;
        if (napi_get_value_string_utf8(env, property_name, key_name, sizeof(key_name), &key_len) != napi_ok) {
            LOGERROR("Get string failed!");
            return false;
        }
        napi_value property_value;
        if (napi_get_property(env, data, property_name, &property_value) != napi_ok) {
            LOGERROR("Get property failed!");
            return false;
        }
        if (!ValidateDataAgainstSchema(env, property_value, value_schema)) {
            all_valid = false;
        }
    }
    return all_valid;
}

bool AvroTypeC::ValidateUnion(napi_env env, napi_value data, avro_schema_t schema) {
    int branch_count = avro_schema_union_size(schema);
    if (branch_count == 0) {
        LOGERROR("No branch is defined for the union type！");
        return false;
    }
    napi_valuetype value_type;
    if (napi_typeof(env, data, &value_type) != napi_ok) {
        LOGERROR("Get type failed!");
        return false;
    }

    if (value_type == napi_null) {
        for (int i = 0; i < branch_count; i++) {
            avro_schema_t branch = avro_schema_union_branch(schema, i);
            if (branch->type == AVRO_NULL) {
                return true;
            }
        }
        LOGERROR("[%{public}s] The null value does not match any branch of the union！", __func__);
        return false;
    }

    for (int i = 0; i < branch_count; i++) {
        avro_schema_t branch = avro_schema_union_branch(schema, i);
        avro_type_t branch_type = branch->type;

        if (branch_type == AVRO_NULL) {
            continue;
        }

        if (ValidateDataAgainstSchema(env, data, branch)) {
            return true;
        }
    }

    return false;
}

bool AvroTypeC::IsTheArrayType(napi_env env, napi_value data, napi_valuetype type) {
    bool isArray;
    napi_is_array(env, data, &isArray);
    if (!isArray) {
        LOGERROR("Is not array!");
        return false;
    }
    uint32_t length;
    if (napi_get_array_length(env, data, &length) != napi_ok) {
        LOGERROR("Get length failed!");
        return false;
    }
    if (length <= 0) {
        return false;
    }
    for (uint32_t i = 0; i < length; i++) {
        napi_value element;
        if (napi_get_element(env, data, i, &element) != napi_ok) {
            LOGERROR("Get element failed!");
            return false;
        }
        napi_valuetype elType;
        napi_typeof(env, element, &elType);
        if (elType != type) {
            LOGERROR("Is not %{public}d !", type);
            return false;
        }
    }
    return true;
}
bool AvroTypeC::ValidateBytes(napi_env env, napi_value data) {
    napi_valuetype type;
    napi_typeof(env, data, &type);
    if (type != napi_object) {
        LOGERROR("Is not bytes!");
        return false;
    }
    bool is_typedarray;
    napi_status status = napi_is_typedarray(env, data, &is_typedarray);
    if (status == napi_ok && is_typedarray) {
        napi_typedarray_type array_type;
        status = napi_get_typedarray_info(env, data, &array_type, nullptr, nullptr, nullptr, nullptr);
        if (status == napi_ok && array_type == napi_uint8_array) {
            return true;
        }
        return false;
    }
    return IsTheArrayType(env, data, napi_number);
}

bool AvroTypeC::ValidateFixed(napi_env env, napi_value data, avro_schema_t schema) {
    napi_valuetype type;
    napi_typeof(env, data, &type);
    if (type != napi_object) {
        LOGERROR("Is not fixed!");
        return false;
    }

    size_t fixed_size = avro_schema_fixed_size(schema);
    size_t data_length = 0;
    napi_status status;

    // 处理传过来是类型数组
    bool is_typedarray;
    napi_is_typedarray(env, data, &is_typedarray);
    if (is_typedarray) {
        napi_typedarray_type array_type;
        status = napi_get_typedarray_info(env, data, &array_type, &data_length, nullptr, nullptr, nullptr);
        if ((status == napi_ok) && (array_type == napi_uint8_array) && (data_length == fixed_size)) {
            return true;
        }
        LOGERROR("[%{public}s] The fixed length does not match ！", __func__);
        return false;
    }

    // 处理传过来是数组
    bool isNumberArray = IsTheArrayType(env, data, napi_number);
    if (isNumberArray) {
        uint32_t length = 0;
        if (napi_get_array_length(env, data, &length) != napi_ok) {
            LOGERROR("Get length failed!");
            return false;
        }
        if (length == fixed_size) {
            return true;
        }
        LOGERROR("The fixed length does not match ！");
    }
    return false;
}

bool AvroTypeC::ValidateEnum(napi_env env, napi_value data, avro_schema_t schema) {
    napi_valuetype type;
    napi_typeof(env, data, &type);
    if (type != napi_string) {
        LOGERROR("Is not enum!");
        return false;
    }
    char enum_value[256];
    size_t value_len;
    if (napi_get_value_string_utf8(env, data, enum_value, sizeof(enum_value), &value_len) != napi_ok) {
        LOGERROR("Get string failed!");
        return false;
    }
    std::string value_str(enum_value, value_len);

    int symbol_count = avro_schema_enum_number_of_symbols(schema);
    for (int i = 0; i < symbol_count; i++) {
        const char *symbol = avro_schema_enum_get(schema, i);
        if (value_str == symbol) {
            return true;
        }
    }

    return false;
}

bool AvroTypeC::ValidateDataAgainstSchema(napi_env env, napi_value data, avro_schema_t schema) {
    switch (schema->type) {
    case AVRO_RECORD:
        return ValidateRecord(env, data, schema);
    case AVRO_STRING:
        return ValidateString(env, data);
    case AVRO_INT32:
    case AVRO_INT64:
    case AVRO_FLOAT:
    case AVRO_DOUBLE:
        return ValidateNumber(env, data);
    case AVRO_BOOLEAN:
        return ValidateBoolean(env, data);
    case AVRO_ARRAY:
        return ValidateArray(env, data, schema);
    case AVRO_MAP:
        return ValidateMap(env, data, schema);
    case AVRO_UNION:
        return ValidateUnion(env, data, schema);
    case AVRO_BYTES:
        return ValidateBytes(env, data);
    case AVRO_FIXED:
        return ValidateFixed(env, data, schema);
    case AVRO_ENUM:
        return ValidateEnum(env, data, schema);
    default:
        return false;
    }
}

napi_value AvroTypeC::IsValid(napi_env env, napi_callback_info info) {
    napi_value result;
    size_t argc = 1;
    napi_value args[1];
    napi_value jsthis;
    napi_status status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr);
    if (status != napi_ok || argc < 1) {
        LOGERROR("Get cb failed！");
        return nullptr;
    }

    AvroTypeC *obj;
    status = napi_unwrap(env, jsthis, (void **)&obj);
    if (status != napi_ok) {
        LOGERROR("Failed to napi_unwrap");
        return nullptr;
    }

    bool isValid = ValidateDataAgainstSchema(env, args[0], obj->schema_);
    status = napi_get_boolean(env, isValid, &result);
    if (status != napi_ok) {
        LOGERROR("Failed to create boolean!");
        return nullptr;
    }

    return result;
}

bool AvroTypeC::ValidateNull(napi_env env, napi_value data) {
    bool result;
    napi_value null_value;
    napi_status status = napi_get_null(env, &null_value);
    TOBUFFER_STATUS_CHECK(status);

    status = napi_strict_equals(env, data, null_value, &result);
    TOBUFFER_STATUS_CHECK(status);

    return result;
}

napi_value AvroTypeC::GetSchema(napi_env env, napi_callback_info info) {
    napi_value jsthis;
    napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr);
    if (status != napi_ok) {
        LOGERROR("Get cb failed!");
        return nullptr;
    }

    AvroTypeC *obj;
    status = napi_unwrap(env, jsthis, (void **)&obj);
    if (status != napi_ok) {
        LOGERROR("Unwrap failed!");
        return nullptr;
    }

    napi_value result;
    status = napi_create_string_utf8(env, obj->avroStr_.c_str(), NAPI_AUTO_LENGTH, &result);
    if (status != napi_ok) {
        LOGERROR("Create string failed!");
        return nullptr;
    }

    return result;
}

std::vector<std::string> AvroTypeC::ExtractAliases(const std::string &jsonStr) {
    std::vector<std::string> aliases;

    // 匹配"aliases"字段对应的数组部分
    std::regex aliasRegex(R"("aliases"\s*:\s*\[(.*?)\])");
    std::smatch aliasMatch;

    if (regex_search(jsonStr, aliasMatch, aliasRegex) && aliasMatch.size() > 1) {
        // 提取数组内部内容
        std::string arrayContent = aliasMatch[1].str();

        // 从数组内容中提取每个字符串元素
        std::regex elemRegex(R"delimiter("([^"]*)")delimiter");
        std::sregex_iterator iter(arrayContent.begin(), arrayContent.end(), elemRegex);
        std::sregex_iterator end;

        // 遍历所有匹配的元素
        for (; iter != end; ++iter) {
            if (iter->size() > 1) {
                aliases.push_back((*iter)[1].str());
            }
        }
    }

    return aliases;
}

napi_value AvroTypeC::GetAliases(napi_env env, napi_callback_info info) {
    napi_value jsthis;
    napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr);
    if (status != napi_ok) {
        LOGERROR("Get cb failed!");
        return nullptr;
    }

    AvroTypeC *obj;
    status = napi_unwrap(env, jsthis, (void **)&obj);
    if (status != napi_ok) {
        LOGERROR("Unwrap failed!");
        return nullptr;
    }
    std::vector<std::string> aliases = ExtractAliases(obj->avroStr_);

    napi_value js_obj;
    status = napi_create_array(env, &js_obj);
    if (status != napi_ok) {
        LOGERROR("创建JavaScript对象失败");
        return nullptr;
    }

    for (int32_t i = 0; i < aliases.size(); ++i) {
        napi_value result;
        status = napi_create_string_utf8(env, aliases[i].c_str(), NAPI_AUTO_LENGTH, &result);
        if (status != napi_ok) {
            LOGERROR("Create string failed!");
            return nullptr;
        }
        napi_set_element(env, js_obj, (uint32_t)i, result);
    }

    return js_obj;
}